package cn.itcast.account.service.impl;

import cn.itcast.account.entity.Account;
import cn.itcast.account.entity.AccountFreeze;
import cn.itcast.account.mapper.AccountFreezeMapper;
import cn.itcast.account.mapper.AccountMapper;
import cn.itcast.account.service.AccountTCCService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;



/**
 * @author liudo
 * @version 1.0
 * @project seata-demo
 * @description
 * @date 2023/8/24 14:15:54
 */
@Service
@RequiredArgsConstructor
public class AccountTCCServiceImpl implements AccountTCCService {

    private final AccountMapper accountMapper;

    private final AccountFreezeMapper accountFreezeMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deduct(String userId, int money) {
        String xid = RootContext.getXID();
        // 解决业务悬挂问题
        // 如果已经有回滚记录了，我们这里无需再扣费
        AccountFreeze accountFreezeExist = accountFreezeMapper.selectById(xid);
        if (Objects.nonNull(accountFreezeExist)) {
            return;
        }
        // 正常冻结资源
        // 1. 扣钱
        Account account = accountMapper.selectOne(
                new LambdaQueryWrapper<Account>()
                        .eq(Account::getUserId, userId)
        );
        if (account.getMoney() < money) {
            // 抛异常金额不足
            throw new RuntimeException("金额不足");
        }
        account.setMoney(account.getMoney() - money);
        accountMapper.updateById(account);
        // 2. 把钱冻结
        AccountFreeze accountFreeze = new AccountFreeze();
        accountFreeze.setXid(xid);
        accountFreeze.setUserId(userId);
        accountFreeze.setFreezeMoney(money);
        accountFreeze.setState(AccountFreeze.State.TRY);
        accountFreezeMapper.insert(accountFreeze);

    }

    @Override
    public boolean commit(BusinessActionContext context) {
        // 手动提交资源
        String xid = context.getXid();
        accountFreezeMapper.deleteById(xid);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean rollback(BusinessActionContext context) {
        // 空回滚 - 直接调用滚动，但是没有执行冻结
        // 手动回滚资源
        // 1. 查询冻结金额
        String xid = context.getXid();
        AccountFreeze accountFreeze = accountFreezeMapper.selectById(xid);
        if (Objects.isNull(accountFreeze)) {
            // 进行空回滚操作了 - 增加一条回滚过的记录
            String userId = context.getActionContext("userId", String.class);
            accountFreeze = new AccountFreeze();
            accountFreeze.setXid(xid);
            accountFreeze.setUserId(userId);
            accountFreeze.setFreezeMoney(0);
            accountFreeze.setState(AccountFreeze.State.CANCEL);
            accountFreezeMapper.insert(accountFreeze);
            return false;
        }

        // 2. 回滚冻结金额
        Account account = accountMapper.selectOne(
                new LambdaQueryWrapper<Account>()
                        .eq(Account::getUserId, accountFreeze.getUserId())
        );
        account.setMoney(account.getMoney() + accountFreeze.getFreezeMoney());
        accountMapper.updateById(account);
        // 3. 更新冻结金额的状态
        accountFreeze.setState(AccountFreeze.State.CANCEL);
        accountFreezeMapper.updateById(accountFreeze);
        return true;
    }
}
